/*
 * Copyright 2014 Will Dignazio
 */
#include "internal.h"
#include <stdlib.h>
#include <leveldb/c.h>

struct Disk
{
	char*	path;
	leveldb_t* ldb;
	leveldb_options_t* ldb_opt;
	leveldb_readoptions_t* ldb_ropt;
	leveldb_writeoptions_t* ldb_wopt;
};

int
disk_write(UCacheObj *obj, Disk *disk, Error *err)
{
	char *errstr;
	MHash mid;

	errstr = NULL;

	mid = mhash(obj, obj->bufsz);
	if(disk->ldb == NULL) {
		ewarn("LevelDB not open for writing\n");
		return -1;
	}

	leveldb_put(disk->ldb, disk->ldb_wopt,
		    (const char*)&mid.hash, sizeof(mid.hash),
		    (const char*)&obj->co_ref.cbuf, sizeof(obj->bufsz),
		    &errstr);

	if(errstr != NULL) {
		error(err, "Failed to write data to disk: %s\n", errstr);
		return -1;
	}

	return 0;
}

int
disk_open(const char *path, Disk** indisk, Error *err)
{
	Disk* disk;
	leveldb_options_t* options;
	leveldb_writeoptions_t* woptions;
	leveldb_readoptions_t* roptions;
	char* errstr;
	int ret;

	ret = -1;
	errstr = NULL;

	disk = malloc(sizeof(*disk));
	if(disk == NULL) {
		esys(err, "Failed to allocate space for Disk: %s\n", path);
		goto fail;
	}
	
	options = leveldb_options_create();
	leveldb_options_set_create_if_missing(options, 1);

	disk->ldb = leveldb_open(options, path, &errstr);
	if(errstr != NULL) {
		error(err, "Failed to open disk: %s\n", errstr);
		goto fail;
	}

	woptions = leveldb_writeoptions_create();
	roptions = leveldb_readoptions_create();

	disk->ldb_opt = options;
	disk->ldb_ropt = roptions;
	disk->ldb_wopt = woptions;
	*indisk = disk;
fail:
	return ret;
}

int
disk_close(Disk *disk, Error *err)
{
	if(disk == NULL) {
		ewarn("Attempted to free NULL disk\n");
		return -1;
	}
	
	leveldb_close(disk->ldb);
	leveldb_free(disk->ldb_opt);
	leveldb_free(disk->ldb_ropt);
	leveldb_free(disk->ldb_wopt);

	return 0;
}
